<?php
/**
 * +----------------------------------------------------------------------
 * | WebSocket服务控制器
 * +----------------------------------------------------------------------
 *                      _ooOoo_
 *                     o8888888o            | AUTHOR: 杜云
 *                     88" . "88            | EMAIL: 987772927@qq.com
 *                     (| -_- |)            | QQ: 987772927
 *                     O\  =  /O            | WECHAT: 987772927
 *                  ____/`---'\____
 *                .'  \\|     |//  `.
 *               /  \\|||  :  |||//  \
 *              /  _||||| -:- |||||-  \
 *              |   | \\\  -  /// |   |
 *              | \_|  ''\-/''  |   |
 *              \  .-\__  `-`  ___/-. /
 *            ___`. .'  /-.-\  `. . __
 *         ."" '<  `.___\_<|>_/___.'  >'"".
 *        | | :  `- \`.;`\ _ /`;.`/ - ` : | |
 *        \  \ `-.   \_ __\ /__ _/   .-` /  /
 *   ======`-.____`-.___\_____/___.-`____.-'======
 *                      `=-='
 * +----------------------------------------------------------------------
 */
declare(strict_types=1);
namespace App\Controller\Server;

use Hyperf\Di\Annotation\Inject;
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnMessageInterface;
use Hyperf\Contract\OnOpenInterface;
use Swoole\Http\Request;
use Swoole\Server;
use Swoole\Websocket\Frame;

use App\Service\SocketClientService;
use App\Event\TalkEvent;
use App\Constants\TalkEventConstant;
use App\Service\Message\ReceiveHandleService;

class WebSocketController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
{
    #[Inject]
    protected SocketClientService $client;
    #[Inject]
    protected ReceiveHandleService $receiveHandle;
    /**
     * 连接创建成功回调事件
     *
     * @param Response|Server $server
     * @param Request         $request
     */
    public function onOpen($server, Request $request): void
    {
        $server->push($request->fd, json_encode([
            "event"   => "connect",
            "content" => [],
        ]));
        // 当前连接的用户
        $user_id = auth('sso')->id();

        // 获取日志实例，记录日志
        stdout_log()->notice("用户连接信息 : user_id:{$user_id} | fd:{$request->fd} 时间：" . date('Y-m-d H:i:s'));
        // 判断是否存在异地登录
        $isOnline = $this->client->isOnlineAll($user_id);
        // 绑定fd与用户关系
        $this->client->bind($request->fd, $user_id);

        // // 加入群聊
        // $groupIds = di()->get(GroupMemberService::class)->getUserGroupIds($user_id);
        // foreach ($groupIds as $group_id) {
        //     SocketRoom::getInstance()->addRoomMember(strval($group_id), strval($user_id));
        // }

        // if (!$isOnline) {
        //     event()->dispatch(new TalkEvent(TalkEventConstant::EVENT_LOGIN, [
        //         'user_id' => $user_id,
        //         'status'  => 1,
        //     ]));
        // }
    }

    /**
     * 消息接收回调事件
     *
     * @param Response|Server $server
     * @param Frame           $frame
     */
    public function onMessage($server, Frame $frame): void
    {
        if (!$frame->data) return;
        $result = json_decode($frame->data, true);
        // 判断是否为心跳检测
        if ($result['event'] == 'heartbeat') {
            $server->push($frame->fd, json_encode(['event' => "heartbeat", 'content' => "pong"]));
            return;
        }
        if (!isset(ReceiveHandleService::EVENTS[$result['event']])) return;
        // 回调处理
        call_user_func_array([$this->receiveHandle, ReceiveHandleService::EVENTS[$result['event']]], [
            $server, $frame, $result['data']
        ]);
    }

    /**
     * 连接创建成功回调事件
     *
     * @param Response|\Swoole\Server $server
     * @param int                     $fd
     * @param int                     $reactorId
     */
    public function onClose($server, int $fd, int $reactorId): void
    {
        $user_id = $this->client->findFdUserId($fd);
        stdout_log()->notice("客户端FD:{$fd} 已关闭连接 ，用户ID为【{$user_id}】，关闭时间：" . date('Y-m-d H:i:s'));
        // 删除 fd 绑定关系
        $this->client->unbind($fd);
        // 判断是否存在异地登录
        $isOnline = $this->client->isOnlineAll($user_id);
        if ($isOnline) return;
        // event()->dispatch(new TalkEvent(TalkEventConstant::EVENT_LOGIN, [
        //     'user_id' => $user_id,
        //     'status'  => 0,
        // ]));
    }
}